Nesse notebook, recriamos um dos gráficos de mais famosos de William Playfair, o inventor do gráfico de linha, área e barras, usando ferramentas atuais como Pandas e Plotly.
Como tarefa 2 do curso, devíamos recriar uma visualização histórica. Para isso, escolhi a visualização de um dos gráficos de William Playfair - o inventor do gráfico de linha, área e barras, bem como posteriormente do gráfico de pizza. O gráfico, feito em 1821, mostra a evolução da economia da Inglaterra através da representação visual do preço do trigo e do salário médio semanal de um mecânico.
Nessa tarefa, o principal desafio foi desenvolver a habilidade de dobrar as ferramentas modernas para criar uma visualização específica já determinada, imitando a liberdade que o autor original possuia. Por isso, muitas técnicas não convecionais precisaram ser utilizadas para criar peças gráficas que se assemelhassem à original. Dentre estas, podemos destacar:
Apesar das gambiarras, espero que goste haha :D
# import tools and get data
import pandas as pd
import plotly.graph_objects as go
import plotly.express as px
df = pd.read_csv('Playfair.csv', sep=';')
for i in df.columns:
df[i] = df[i].str.replace(',', '.').astype(float)
df['year'] = df.index*5 + 1565
df = df.drop(columns=['Wages'])
df_wages = pd.read_csv('Playfair_wages.csv', sep=';')
for i in df_wages.columns:
df_wages[i] = df_wages[i].str.replace(',', '.').astype(float)
df_wages['year'] = df_wages.index + 1565
# plot the bars for the wheat prices
def create_gradient(df, col):
# at first, add a bar to set the color of the legend
fig.add_trace(
go.Bar(
x=df['year'],
y=df[col],
marker=dict(
color='#4a6082',
line=dict(width=0)
),
name = 'Wheat price',
legendgroup = 'Wheat price',
)
)
colors = ["#4a6082", "#5f7393", "#7486a3", "#c5cedb", "#e2e7ed"]
for i in range(5):
new_df = df.copy()
new_df[col] = new_df[col]*(((5-i)/5)**(3/5))
fig.add_trace(
go.Bar(
x=new_df['year'],
y=new_df[col],
marker=dict(
color=colors[i],
line=dict(width=1, color=colors[i])
),
hoverinfo = 'none',
showlegend=False,
legendgroup = 'Wheat price'
)
)
# at last, add a transparent bar for hoverinfo
fig.add_trace(
go.Bar(
x=df['year'],
y=df[col],
marker=dict(
color='rgba(0,0,0,0)',
line=dict(width=0)
),
hovertext = [f"<b>Year:</b> {df['year'][i]}; <br>\
<b>Price:</b> ${df['Weat'][i]}." for i in df.index],
name = 'Wheat price',
showlegend=False,
legendgroup = 'Wheat price',
)
)
# plot the area for the wages
def create_area(df, col):
fig.add_trace(
go.Scatter(
x=df['year'],
y=df[col],
mode='lines',
line=dict(width=2, color='#ff6e61'),
fillcolor = '#b8d7e6',
stackgroup='one',
name = "Wages",
hovertext = [f"<b>Year:</b> {df['year'][i]}; <br>\
<b>{col}:</b> ${df[col][i]}." for i in df.index],
)
)
# create the lines in the figure
def create_lines(fig):
# create vertical lines
for i in [1600, 1650, 1700, 1750, 1800]:
fig.add_trace(
go.Scatter(
x=[i, i],
y=[0, 100],
mode='lines',
line=dict(width=1, color='black'),
showlegend=False,
hoverinfo='none'
)
)
# create horizontal lines
for i in [0, 20, 40, 60, 80, 100]:
fig.add_trace(
go.Scatter(
x=[1565, 1821],
y=[i, i],
mode='lines',
line=dict(width=1, color='gray'),
showlegend=False,
hoverinfo='none'
)
)
# create the reigns timeline in the top of the figure and suplementar text
def create_timeline(fig):
fig.add_annotation(
x=1750,
y=8,
text="<i><b>Weekly Wages of a Good Mechanic</i></b>",
showarrow=False,
font=dict(
size=12,
color="black"
)
)
fig.add_shape(
type="rect",
x0=1565,
y0=97,
x1=1603,
y1=96,
fillcolor="black",
)
fig.add_annotation(
x=1585,
y=92,
text="Elizabeth I",
showarrow=False,
font=dict(
size=12,
color="black"
)
)
fig.add_shape(
type="rect",
x0=1603,
y0=96,
x1=1625,
y1=95,
fillcolor="black",
)
fig.add_annotation(
x=1615,
y=91,
text="James I",
showarrow=False,
font=dict(
size=12,
color="black"
)
)
fig.add_shape(
type="rect",
x0=1625,
y0=97,
x1=1649,
y1=96,
fillcolor="black",
)
fig.add_annotation(
x=1637,
y=92,
text="Charles I",
showarrow=False,
font=dict(
size=12,
color="black"
)
)
fig.add_shape(
type="rect",
x0=1649,
y0=96,
x1=1660,
y1=95,
fillcolor="black",
)
fig.add_annotation(
x=1655,
y=91,
text="Commonwealth",
showarrow=True,
font=dict(
size=12,
color="black"
)
)
fig.add_shape(
type="rect",
x0=1660,
y0=97,
x1=1685,
y1=96,
fillcolor="black",
)
fig.add_annotation(
x=1673,
y=92,
text="Charles II",
showarrow=False,
font=dict(
size=12,
color="black"
)
)
fig.add_shape(
type="rect",
x0=1685,
y0=96,
x1=1702,
y1=95,
fillcolor="black",
)
fig.add_annotation(
x=1694,
y=91,
text="James II",
showarrow=False,
font=dict(
size=12,
color="black"
)
)
fig.add_shape(
type="rect",
x0=1702,
y0=97,
x1=1714,
y1=96,
fillcolor="black",
)
fig.add_annotation(
x=1708,
y=91,
text="William III",
showarrow=True,
font=dict(
size=12,
color="black"
)
)
fig.add_shape(
type="rect",
x0=1714,
y0=96,
x1=1727,
y1=95,
fillcolor="black",
)
fig.add_annotation(
x=1721,
y=91,
text="Anne",
showarrow=False,
font=dict(
size=12,
color="black"
)
)
fig.add_shape(
type="rect",
x0=1727,
y0=97,
x1=1760,
y1=96,
fillcolor="black",
)
fig.add_annotation(
x=1744,
y=92,
text="George I",
showarrow=False,
font=dict(
size=12,
color="black"
)
)
fig.add_shape(
type="rect",
x0=1760,
y0=96,
x1=1820,
y1=95,
fillcolor="black",
)
fig.add_annotation(
x=1790,
y=91,
text="George III",
showarrow=False,
font=dict(
size=12,
color="black"
)
)
# create the elipse title
def create_title(fig):
fig.add_shape(
type="circle",
x0=1598,
y0=91,
x1=1702,
y1=54,
fillcolor="white",
line_color="black",
line_width=2,
)
fig.add_annotation(
x=1650,
y=87,
text="Chart",
showarrow=False,
font=dict(
size=30,
color="black"
)
)
fig.add_annotation(
x=1650,
y=70,
text="""
Showing at One View <br> \
The price of the Quarter of the Wheat <br> \
& Wages of labor by Week. <br> \
--- From --- <br> \
The year 1565 to 1821 <br> \
--- By --- <br> \
<b>William Playfair</b>""",
showarrow=False,
font=dict(
size=9,
color="black"
)
)
fig = go.Figure()
# create bar plot with gradient for Weat
create_gradient(df, 'Weat')
# create area plot for Wages
create_area(df_wages, 'Wages')
# create vertical and horizontal lines
create_lines(fig)
# create texts
create_timeline(fig)
# create title
create_title(fig)
# set figure layout
fig.update_layout(
xaxis_range=[1565, 1821],
yaxis_range=[0, 100],
barmode='overlay',
bargap=0,
autosize=False,
width=750,
height=500,
font=dict(
family="Times New Roman",
),
)
fig.show()